Error Handling
In Go, error handling is explicit — meaning you have to manually check and handle errors instead of relying on exceptions (like in Java, Python, or C#). Errors in Go are values, and they follow the "error is just another return value" philosophy.
Go uses the built-in error interface for errors.
type error interface {
Error() string
}
If a function can fail, it usually returns two values:
- The result (if successful, otherwise zero value)
- An error (if something went wrong, otherwise
nil)
Creating and Returning Errors
We can create an error using the errors.New() function from the errors package or fmt.Errorf().
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("division by zero is not allowed")
}
return a / b, nil
}
func main() {
result, err := divide(10, 0)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Println("Result:", result)
}
}
Using fmt.Errorf for Formatted Errors
fmt.Errorf() is like errors.New() but allows formatting:
err := fmt.Errorf("failed to open file %s: %v", filename, originalErr)
Custom Error Types
You can create your own error type by implementing the Error() method.
type MyError struct {
Code int
Message string
}
func (e *MyError) Error() string {
return fmt.Sprintf("Error %d: %s", e.Code, e.Message)
}
func doSomething() error {
return &MyError{Code: 404, Message: "Not Found"}
}
func main() {
err := doSomething()
if err != nil {
fmt.Println(err)
}
}
- Allows attaching extra information (like codes, timestamps, etc.)
- Makes error checking more specific.
Error Wrapping (%w)
Go 1.13+ supports error wrapping, letting you chain error contexts.
import (
"errors"
"fmt"
)
func readConfig() error {
return errors.New("file missing")
}
func loadApp() error {
return fmt.Errorf("loadApp failed: %w", readConfig())
}
func main() {
err := loadApp()
fmt.Println(err) // Prints: loadApp failed: file missing
}
Checking Specific Errors (errors.Is and errors.As)
Sometimes you want to check what kind of error happened.
import (
"errors"
"fmt"
)
var ErrNotFound = errors.New("not found")
func search() error {
return ErrNotFound
}
func main() {
err := search()
if errors.Is(err, ErrNotFound) {
fmt.Println("Item not found.")
}
}
Panic vs Error
- Error → Recoverable problems; expected to happen sometimes.
- Panic → Unrecoverable problems; program should stop immediately.
- Use
panic()rarely (e.g., initialization failures, corrupted state). - You can recover from panics using
recover(), but that’s mainly for critical failure safety nets.